/*
 * Copyright (c) 2001-2007, Inversoft, All Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package org.inversoft.vertigo.guice;

import javax.persistence.EntityManager;
import javax.servlet.ServletContext;

import org.acegisecurity.providers.dao.SaltSource;
import org.acegisecurity.providers.dao.salt.SystemWideSaltSource;
import org.acegisecurity.providers.encoding.Md5PasswordEncoder;
import org.acegisecurity.providers.encoding.PasswordEncoder;
import org.apache.commons.configuration.Configuration;
import org.inversoft.vertigo.config.EnvironmentAwareConfiguration;
import org.inversoft.vertigo.jpa.EntityManagerProvider;
import org.inversoft.vertigo.security.SecurityContext;
import org.inversoft.vertigo.servlet.ServletContextHolder;

import com.google.inject.Provider;

/**
 * <p>
 * This is the default module that most applications that use
 * Vertigo will either use or extend from or use in a composite
 * environment.
 * </p>
 *
 * @author  James Humphrey and Brian Pontarelli
 */
public class VertigoWebModule extends VertigoConfigurationModule {
    /**
     * Configures the Guice injector. This calls these methods in this order:
     *
     * <ol>
     * <li>{@link super#configure()}</li>
     * <li>{@link #configureJPA()}</li>
     * <li>{@link #configureACEGI()}</li>
     * <li>{@link #configureSecurityProvider()}</li>
     * <li>{@link #configureConfiguration()}</li>
     * <li>{@link #configureServletContext()}</li>
     * </ol>
     */
    protected void configure() {
        super.configure();
        configureJPA();
        configureACEGI();
        configureSecurityProvider();
        configureConfiguration();
        configureServletContext();
    }

    /**
     * Configures the servlet context for injection.
     */
    protected void configureServletContext() {
        // Bind the servlet context
        bind(ServletContext.class).toInstance(ServletContextHolder.getServletContext());
    }

    /**
     * Configures the Apache Commons {@link Configuration} for injection.
     */
    protected void configureConfiguration() {
        // Setup the configuration
        bind(Configuration.class).to(EnvironmentAwareConfiguration.class);
    }

    /**
     * Configures the {@link SecurityContext} so that it correctly has a SecurityContextProvider
     * injected. This is done via static injection on the {@link SecurityContext} class.
     */
    protected void configureSecurityProvider() {
        // Initialize the static ACEGI security provider
        requestStaticInjection(SecurityContext.class);
    }

    /**
     * Configures the ACEGI classes necessary for registration. This is usually a {@link PasswordEncoder}
     * which is an MD5 password encoder by default and a {@link SaltSource}, which is a system wide
     * salt source. This method invokes the {@link #salt()} method to fetch the salt. Sub-classes
     * should implement that method to provide a better salt.
     */
    protected void configureACEGI() {
        // Setup the ACEGI classes
        bind(PasswordEncoder.class).toProvider(new Provider<PasswordEncoder>() {
            public PasswordEncoder get() {
                Md5PasswordEncoder encoder = new Md5PasswordEncoder();
                encoder.setEncodeHashAsBase64(true);
                return encoder;
            }
        });
        bind(SaltSource.class).toProvider(new Provider<SaltSource>() {
            public SaltSource get() {
                SystemWideSaltSource ss = new SystemWideSaltSource();
                ss.setSystemWideSalt(salt());
                return ss;
            }
        });
    }

    /**
     * @return  Returns the default salt of <strong>vertigo</strong>.
     */
    protected String salt() {
        return "vertigo";
    }

    /**
     * Sets up the JPA {@link EntityManagerProvider}.
     */
    protected void configureJPA() {
        bind(EntityManager.class).toProvider(new EntityManagerProvider());
    }
}
